home *** CD-ROM | disk | FTP | other *** search
/ Maclife 157 / MACLIFE157-2001-09.ISO.7z / MACLIFE157-2001-09.ISO / Linux / MacOS Tools / BootX 1.2.2 / Sources / src / common / boot.c next >
Text File  |  2001-07-23  |  43KB  |  1,569 lines

  1. /* BootX
  2.  *
  3.  * Written by Benjamin Herrenschmidt
  4.  *
  5.  * portions of this code from InfiniteOS boot loader by <...>, portions from
  6.  * quik by Paul Mackerras.
  7.  *
  8.  * GPL....
  9.  *
  10.  * This file contains all the code involved in loading kernels, ramdisks,
  11.  * preparing the boot environement and doing the actual boot.
  12.  * It's shared between BootX and miBoot
  13.  *
  14.  */
  15.  
  16. #include <Types.h>
  17. #include <NameRegistry.h>
  18. #include <Processes.h>
  19. #include <ShutDown.h>
  20. #include <Files.h>
  21. #include <Devices.h>
  22. #include <Errors.h>
  23. #include <LowMem.h>
  24. #include <Gestalt.h>
  25.  
  26. #include "boot.h"
  27.  
  28. #include "uLibc.h"
  29. #include "debug_text.h"
  30. #include "zlib.h"
  31. #include "elf_loader_defs.h"
  32. #include "extract_dev_tree.h"
  33. #include "bootx.h"
  34. #include "LowLevelBoot.h"
  35. #include "rs6000.h"
  36. #include "boot.h"
  37.  
  38. /* This should be exported by someone else */
  39. extern dt_context*    dct;
  40. extern Boolean        g_arch_PCI;
  41.  
  42. /* --- Local definitions */
  43. #define DEBUG        1
  44.  
  45. #define get_16be(x)    (*(unsigned short *)(x))
  46. #define get_32be(x)    (*(unsigned long *)(x))
  47.  
  48. #define NAME_REGISTRY_MAX_SIZE        (128UL * 1024UL)            // 128Kb: Size pre-allocated for holding name registry
  49. #define BOOT_KERNEL_STACK_SIZE        65536                        // initial stack
  50. #define TEMP_BUFFER_SIZE            1024
  51.  
  52. /* Alignement macros */
  53. #define PAGE_ALIGN(x)    ((((UInt32)(x)) + g_page_size - 1) & (-g_page_size))
  54. #define LINE_ALIGN(x)    ((((UInt32)(x)) + 32 - 1) & (-32))
  55. #define BI_OFFSET(x)    (offsets[x] - offsets[offset_bootinfo])
  56.  
  57. /* MacOS nanokernel data structures */
  58. #define MACOS_MEMMAP_PTR_ADDR        0x5FFFEFF0    
  59. #define MACOS_MEMMAP_SIZE_ADDR        0x5FFFEFF6    
  60. #define MACOS_MEMMAP_BANK_0FFSET    48
  61.     
  62. #define kFinderSig 'FNDR'
  63. #define kSystemType 'MACS'
  64.  
  65. /* Glue resources */
  66. enum {    
  67.     code_boot_glue68k        = 128,
  68.     code_boot_gluePrePPC    = 129,
  69.     code_boot_glueStrapPPC    = 130,
  70.     code_boot_glueBurgundy    = 131
  71. };
  72.  
  73.     
  74. /* Indexes in offset array */
  75. enum
  76. {
  77.     offset_kernel = 0,    /* kernel itself, offset 0 */
  78.     offset_stack,        /* boot stack */
  79.     offset_bootinfo,    /* boot_info */
  80.     offset_arguments,    /* args line */
  81.     offset_color_map,    /* colormap setup by bootx */
  82.     offset_device_tree,    /* device tree */
  83.     offset_ramdisk,        /* optional ramdisk */
  84.     offset_unmangler,    /* unmangler (may be moved higher) */
  85.     offset_count
  86. };
  87.  
  88. /* FIXME ! Page size is currently hard coded. */
  89. static UInt32 g_page_size = 4096;
  90.  
  91. /* Large enough for what we need for check_xxx routines */
  92. static s_temp_buffer[TEMP_BUFFER_SIZE];
  93.  
  94.  
  95. /* --- Static functions prototypes --- */
  96.  
  97. #if BOOTX_ENV == BOOTX_ENV_RAW
  98. UInt8*            get_physical(void* ptr);
  99. #else
  100. static UInt8*    get_physical(void* ptr);
  101. #endif
  102.  
  103. static OSErr    gunzip(void *dst, unsigned int dstlen, unsigned char *src, unsigned int *lenp);
  104. static OSErr    check_elf_kernel(boot_kernel_desc_t* in_desc);
  105. static OSErr    build_pci_device_tree(Ptr devTree, UInt32 *outDevTreeSize, UInt32 *outDispRegOff);
  106. static OSErr    make_resident(void* ptr, unsigned long size, Boolean contiguous);
  107. static void*    load_bootstrap(UInt32 mapSize, UInt32** outMapBegin,UInt32 *outTotalSize);
  108. static Ptr        alloc_high_mem(unsigned long count);
  109. static void        setup_basic_bootinfo(boot_infos_t* bi, UInt32 *out_load_base);
  110. static OSErr    make_kernel_map(Ptr base, UInt32 total_size, UInt32 **out_map, UInt32 *out_size);
  111. static void        build_memory_map(boot_infos_t* bi);
  112. static UInt32    get_temp_page(UInt32 *cur_temp, UInt32 *used_map, UInt32 used_size);
  113. static void        make_kernel_copymap(UInt32* map, UInt32 map_size, UInt32 *map_loc, UInt32 dest_base, UInt32 *temp_page);
  114. static OSErr    send_restart_to_finder(void);
  115. static OSErr    find_finder_process(ProcessSerialNumberPtr processSN);
  116. static OSErr    do_load_glues(Ptr *low_68k_glue, Ptr *low_PPC_glue);
  117. static void        add_l2cr_property(UInt32 l2cr_value);
  118. static void        check_burgundy_patch(void);
  119. static void        debug_checkpoint(void);
  120.  
  121. static OSErr    file_read(boot_file_t *file, UInt32 offset, void *buffer, UInt32 *size);
  122. static OSErr    file_open(boot_file_t *file);
  123. static void        file_close(boot_file_t *file);
  124. static int        my_sscanfld(char *s, unsigned long int *v);
  125.  
  126.  
  127. /* --- Implementation --- */
  128.  
  129. OSErr
  130. file_read(boot_file_t *file, UInt32 offset, void *buffer, UInt32 *size)
  131. {
  132.     ParamBlockRec    pb;
  133.     OSErr            err;
  134.  
  135. #if BOOTX_USES_FILES    
  136.     pb.ioParam.ioRefNum        = file->rn;
  137.     pb.ioParam.ioBuffer        = (Ptr)buffer;
  138.     pb.ioParam.ioReqCount    = (long)*size;
  139.     pb.ioParam.ioPosMode    = fsFromStart;
  140.     pb.ioParam.ioPosOffset    = (long)offset;
  141.     err = PBReadSync(&pb);
  142.     
  143.     *size = (UInt32)pb.ioParam.ioActCount;
  144. #else
  145.  
  146.     // -- NOT YET IMPLEMENTED --    
  147.     
  148. #endif
  149.     
  150.     return err;
  151. }
  152.  
  153. OSErr
  154. file_open(boot_file_t *file)
  155. {
  156. #if BOOTX_USES_FILES
  157.     HParamBlockRec    pb;
  158.     OSErr            err;
  159.     
  160.     pb.ioParam.ioMisc        = NULL;
  161.     pb.fileParam.ioFVersNum    = 0;
  162.     pb.fileParam.ioNamePtr    = file->spec.name;
  163.     pb.fileParam.ioVRefNum    = file->spec.vRefNum;
  164.     pb.fileParam.ioDirID    = file->spec.parID;
  165.     pb.ioParam.ioPermssn    = fsRdPerm;
  166.  
  167.     err = PBHOpenDFSync(&pb);
  168.     if (err == paramErr)
  169.         err = PBHOpenSync(&pb);
  170.     
  171.     file->rn = pb.ioParam.ioRefNum;
  172.     GetEOF(file->rn, (long *)&file->size);
  173.     
  174.     return err;
  175.  
  176. #else
  177.     return (file->rn == -1) notOpenErr : noErr;
  178. #endif    
  179. }
  180.  
  181. void
  182. file_close(boot_file_t *file)
  183. {
  184. #if BOOTX_USES_FILES
  185.     /* FIXME: use PBCloseSync */
  186.     FSClose(file->rn);
  187.     file->rn = -1;
  188. #endif
  189. }
  190.  
  191.  
  192. /* I don't want to include the MSL Standard C librairies, just to scan an offset 
  193.    in the Mach Kernel Image file */
  194. int my_sscanfld(char *s, unsigned long int *v)
  195. {
  196.     char                *c, *pos;
  197.     unsigned long int    i, j;
  198.     
  199.     c = s;
  200.     while (*c && (*c < '0' || *c > '9'))
  201.         c++;
  202.     if (!*c)
  203.         return(0);
  204.     pos = c;
  205.     while (*c >= '0' && *c <= '9')
  206.         c++;
  207.     i = 0;
  208.     for (j = 1, c--; c >= pos; c--) {
  209.         i += ((unsigned long int) (*c - '0')) * j;
  210.         j *= 10;
  211.     }
  212.     if (v) {
  213.         *v = i;
  214.         return(1);
  215.     }
  216.     return(0);
  217. }
  218.  
  219. static check_one_key(KeyMap map, UInt8 key_code)
  220. {
  221.     return ((((UInt8 *)map)[key_code >> 3] >> (key_code & 7)) & 1);
  222. }
  223.  
  224. void
  225. debug_checkpoint(void)
  226. {
  227.     KeyMap    keys;
  228.     
  229.     do {
  230.         GetKeys(keys);
  231.         if (!check_one_key(keys, 0x3a))
  232.             break;
  233.     } while(true);
  234. }
  235.  
  236. static void *
  237. zalloc(void *, unsigned int items, unsigned int size)
  238. {
  239.       Ptr    p = NewPtr(((SInt32)size) * (SInt32)items);
  240.       
  241.       if (!p)
  242.           dt_printf(dct, "#zalloc(%d bytes) failed (err: %d) !",
  243.               (size*items), MemError());
  244.       
  245.       return p;
  246. }
  247.  
  248. static void
  249. zfree(void *, void *addr, unsigned int)
  250. {
  251.     if (addr)
  252.         DisposePtr(addr);
  253. }
  254.  
  255. #define HEAD_CRC    2
  256. #define EXTRA_FIELD    4
  257. #define ORIG_NAME    8
  258. #define COMMENT        0x10
  259. #define RESERVED    0xe0
  260.  
  261. #define DEFLATED    8
  262.  
  263. OSErr
  264. gunzip(void *dst, unsigned int dstlen, unsigned char *src, unsigned int *lenp)
  265. {
  266.     z_stream s;
  267.     int r, i, flags;
  268.  
  269.     /* skip header */
  270.     i = 10;
  271.     flags = src[3];
  272.     if (src[2] != DEFLATED || (flags & RESERVED) != 0) {
  273.         dt_printf(dct, "#gunzip: bad gzipped data¥n");
  274.         return -1;
  275.     }
  276.     if ((flags & EXTRA_FIELD) != 0)
  277.     i = 12 + src[10] + (src[11] << 8);
  278.     if ((flags & ORIG_NAME) != 0)
  279.     while (src[i++] != 0)
  280.         ;
  281.     if ((flags & COMMENT) != 0)
  282.     while (src[i++] != 0)
  283.         ;
  284.     if ((flags & HEAD_CRC) != 0)
  285.     i += 2;
  286.     if (i >= *lenp) {
  287.         dt_printf(dct, "#gunzip: ran out of data in header¥n");
  288.         return -1;
  289.     }
  290.  
  291.     s.zalloc = zalloc;
  292.     s.zfree = zfree;
  293.     r = inflateInit2(&s, -MAX_WBITS);
  294.     if (r != Z_OK) {
  295.         dt_printf(dct, "#gunzip: inflateInit2 returned %d¥n", r);
  296.         return -1;
  297.     }
  298.     s.next_in = src + i;
  299.     s.avail_in = *lenp - i;
  300.     s.next_out = dst;
  301.     s.avail_out = dstlen;
  302.     r = inflate(&s, Z_FINISH);
  303.     if (r != Z_OK && r != Z_STREAM_END) {
  304.         dt_printf(dct, "#gunzip: inflate returned %d¥n", r);
  305.         return -1;
  306.     }
  307.     *lenp = (unsigned int)(s.next_out - (unsigned char *) dst);
  308.     inflateEnd(&s);
  309.        
  310.        return noErr;
  311. }
  312.  
  313. OSErr
  314. build_pci_device_tree(Ptr devTree, UInt32 *outDevTreeSize, UInt32 *outDispRegOff)
  315. {
  316.     OSErr            err;
  317.     
  318.     err = noErr;
  319.     
  320.     *outDevTreeSize = NAME_REGISTRY_MAX_SIZE;
  321.     /* FIXME: We shoud do bound-checking while copying instead of "hoping" that we'll
  322.               have enough room. In practice the 128k we allocate are largely enough
  323.      */
  324.     err = (OSErr)copy_device_tree(devTree, outDevTreeSize, outDispRegOff);
  325.     if (err != noErr && (*outDevTreeSize > NAME_REGISTRY_MAX_SIZE)) {
  326.         dt_printf(dct, "#dev_tree: Device tree overflow ! Your machine is probably crashed now.¥n");
  327.         return err;
  328.     } else if (err != noErr) {
  329.         dt_printf(dct, "#dev_tree: Error %d while copying device tree !¥n", err);
  330.     }
  331.     
  332.     return noErr;    
  333. }
  334.  
  335. OSErr
  336. check_elf_kernel(boot_kernel_desc_t *in_desc)
  337. {
  338.     OSErr        err;
  339.     int         i;
  340.     Elf32_Ehdr    e;
  341.     Elf32_Phdr    *p;
  342.     UInt32        total_file_size;
  343.     UInt32        offset, entry, load_loc;
  344.     UInt32        bootstraptask_offset = 0;
  345.     UInt32        size, ts, f_size;
  346.     char        *t;
  347.  
  348.     if (in_desc->file->rn == -1)
  349.         return notOpenErr;
  350.  
  351.     offset = entry = size = f_size = 0;
  352.     
  353.     total_file_size = in_desc->file->size;
  354.  
  355.     ts = sizeof(Elf32_Ehdr);
  356.     err = file_read(in_desc->file, 0, &e, &ts);
  357.     if (err != noErr) {
  358.         dt_printf(dct, "#check_elf_kernel: can't read header, error %d¥n", err);
  359.         return err;
  360.     }
  361.     t = (char *) &e;
  362.     if (strncmp("MACH_BOOT_IMAGE", t, 15) == 0) {
  363.         char            temp[32];
  364.         unsigned long    a = 32;
  365.         
  366.         err = file_read(in_desc->file, 0, temp, &a);
  367.         if (err != noErr) {
  368.             dt_printf(dct, "#check_elf_kernel: can't read Mach Kernel header, error %d¥n", err);
  369.             return err;
  370.         }
  371.         if (my_sscanfld(temp + 16, &bootstraptask_offset) != 1) {
  372.             dt_printf(dct, "#check_elf_kernel: can't read bootstrap task offset¥n");
  373.             return -1;
  374.         }
  375.         err = file_read(in_desc->file, a, &e, &ts);     
  376.     }
  377.     
  378.     /* Check if it is an executable elf binary. (Redudant but I like it this way)
  379.      */
  380.     if (!(e.e_ident[EI_MAG0] == ELFMAG0 && e.e_ident[EI_MAG1] == ELFMAG1 &&
  381.           e.e_ident[EI_MAG2] == ELFMAG2 && e.e_ident[EI_MAG3] == ELFMAG3)) {
  382.         dt_printf(dct, "#check_elf_kernel: doesn't look like an ELF image !");
  383.         return -1;
  384.     }
  385.     if (e.e_ident[EI_CLASS] != ELFCLASS32
  386.         || e.e_ident[EI_DATA] != ELFDATA2MSB) {
  387.         dt_printf(dct, "#check_elf_kernel:  ELF image is wrong format (not PPC MSB 32) !");
  388.         return -1;
  389.     }
  390.     
  391.     /* Check in the program header */
  392.     i = e.e_phnum;
  393.     /* compensate for eventual alignement */
  394.     while(i) {
  395.         ts = (sizeof(Elf32_Phdr)+4) * i;
  396.         if (ts > TEMP_BUFFER_SIZE) {
  397.             dt_printf(dct, "#skipping ELF section !¥n");
  398.             ts--;
  399.         } else
  400.             break;
  401.     }
  402.     if (ts == 0) {
  403.         dt_printf(dct, "#check_elf_kernel: skipped all sections !!!¥n");
  404.         return memFullErr;
  405.     }
  406.     err = file_read(in_desc->file, e.e_phoff + (bootstraptask_offset?32:0), s_temp_buffer, &ts);
  407.     if (err != noErr) {
  408.         dt_printf(dct, "#check_elf_kernel: error %d reading section headers !¥n");
  409.         return err;
  410.     }
  411.         
  412.     p = (Elf32_Phdr *)(s_temp_buffer);
  413.  
  414.     #define ADDRMASK    0x0fffffff
  415.     
  416.     size = 0;
  417.  
  418.     /* Scan through the program header
  419.      * HACK:  We must return the _memory size of the kernel image, not the
  420.      *        file size (because we have to leave room before other boot
  421.      *      infos. This code works as a side effect of the fact that
  422.      *      we have one section and vaddr == p_paddr
  423.      */
  424.     for (i = 0; i < e.e_phnum; ++i, ++p) {
  425.         if (p->p_type != PT_LOAD || p->p_offset == 0)
  426.             continue;
  427.         if (size == 0) {
  428.             offset = p->p_offset;
  429.             size = p->p_memsz;
  430.             f_size = p->p_filesz;
  431.             load_loc = p->p_vaddr & ADDRMASK;
  432. //            dt_printf(dct, "size (1) : 0x%x¥n", size);
  433.         } else {
  434.             size = p->p_offset + p->p_memsz - offset; /* XXX Bogus */
  435.             f_size = p->p_offset + p->p_filesz - offset;
  436. //            dt_printf(dct, "size (2) : 0x%x¥n", size);
  437.         }
  438.     }
  439.     if (size == 0) {
  440.         dt_printf(dct, "#check_elf_kernel: Can't find a loadable segment !¥n");
  441.         return -1;
  442.     }
  443.     entry = (UInt32)(e.e_entry & ADDRMASK) - load_loc;
  444.     
  445.     dt_printf(dct, "kernel memory size  : %d bytes¥n", size);
  446.     dt_printf(dct, "kernel file offset  : %d bytes¥n", offset);
  447.     dt_printf(dct, "kernel entry_offset : %d bytes¥n", entry);
  448.     in_desc->mem_size = size;
  449.     in_desc->size = f_size;
  450.     in_desc->offset = offset;
  451.     in_desc->entry = entry;
  452.  
  453.     return 0;
  454.  out:
  455.      return -1;
  456. }
  457.  
  458. /* Get the physical address, if possible, of a pointer. Note that
  459.  * we fail silently since we _do_ fail sometimes, like for screen
  460.  * base address. In this case, we just return the original pointer
  461.  */
  462. UInt8*
  463. get_physical(void* ptr)
  464. {
  465.     LogicalToPhysicalTable    table;
  466.     unsigned long            count;
  467.     OSErr                    err;
  468.     
  469.     table.logical.address    = ptr;
  470.     table.logical.count        = 1024;
  471.     count = sizeof( table ) / sizeof( MemoryBlock ) - 1;
  472.     
  473.     err = GetPhysical( &table, &count );
  474.     if ( err != noErr)
  475.         return ptr;
  476.     
  477.     return (UInt8 *)(table.physical[0].address);
  478. }
  479.  
  480. /* Make a portion of memory resident. */
  481. OSErr
  482. make_resident(void* ptr, unsigned long size, Boolean contiguous)
  483. {
  484.     OSErr    err;
  485.     
  486.     if (size % g_page_size)
  487.         size = size + g_page_size - (size % g_page_size);
  488.  
  489.     err = contiguous ? LockMemoryContiguous(ptr, size) : LockMemory(ptr, size);
  490.  
  491. bail:
  492.     if (err != noErr)
  493.         dt_printf(dct, "LockMemory%s failed, err: %d¥n",
  494.             contiguous ? "Contiguous" : "", err);
  495.     return err;
  496. }
  497.  
  498. /* This function will build a simple map of the physical pages used
  499.    by the kernel stuffs
  500.  */
  501. OSErr
  502. make_kernel_map(Ptr base, UInt32 total_size, UInt32 **out_map, UInt32 *out_size)
  503. {
  504.     LogicalToPhysicalTable    table;
  505.     unsigned long            count, i;
  506.     OSErr                    err;
  507.     UInt32                    page_count;
  508.     
  509.     page_count    = total_size / g_page_size;
  510.     
  511.     *out_map = (UInt32 *)NewPtrClear((SInt32)(page_count * sizeof(UInt32)));
  512.     if (*out_map == NULL)
  513.         return memFullErr;
  514.     
  515.     for (i=0; i<page_count; i++) {
  516.         /* First get all physical/logical mappings */    
  517.         table.logical.address    = base + i*g_page_size;
  518.         table.logical.count        = 1024;
  519.         count = sizeof( table ) / sizeof( MemoryBlock ) - 1;
  520.         err = GetPhysical( &table, &count );
  521.         if ( err != noErr)
  522.             return err;
  523.         (*out_map)[i] = (UInt32)table.physical[0].address;
  524.     }
  525.  
  526.     *out_size = page_count;
  527.     
  528.     return noErr;
  529. }
  530.  
  531. /* This function is used on non-PCI machines, it will look into some
  532.    internal MacOS NanoKernel data structures to figure out the physical
  533.    memory map of the machine */
  534. void
  535. build_memory_map(boot_infos_t* bi)
  536. {    
  537.     Ptr base = *((Ptr *)MACOS_MEMMAP_PTR_ADDR);
  538.     UInt32 len = *((UInt16 *)MACOS_MEMMAP_SIZE_ADDR);
  539.     UInt32 i;
  540.     
  541.     if (len <= MACOS_MEMMAP_BANK_0FFSET)
  542.         return;
  543.         
  544.     base += MACOS_MEMMAP_BANK_0FFSET;
  545.     len -= MACOS_MEMMAP_BANK_0FFSET;
  546.     i = 0;
  547.     
  548.     while(len >= 8) {
  549.         UInt32 addr = *((UInt32*)base);
  550.         UInt32 size = *((UInt32*)(base+4));
  551.         
  552.         if (size) {
  553.             if ((i>0) && ((bi->physMemoryMap[i-1].physAddr +
  554.                 bi->physMemoryMap[i-1].size) == addr)) {
  555.                 bi->physMemoryMap[i-1].size += size;
  556.             } else {    
  557.                 bi->physMemoryMap[i].physAddr = addr;
  558.                 bi->physMemoryMap[i].size = size;
  559.                 i++;
  560.             }
  561.         }
  562.         base += 8;
  563.         len -= 8;
  564.     }
  565.     bi->physMemoryMapSize = i;
  566. }
  567.  
  568. void *
  569. load_bootstrap(UInt32 mapSize, UInt32** outMapBegin,UInt32 *outTotalSize)
  570. {
  571. //#if BOOTX_ENV == BOOTX_ENV_RAW
  572.     // --- NOT YET IMPLEMENTED
  573. //#else    
  574.     Handle                krsrc;
  575.     OSErr                err;
  576.     CFragConnectionID    fragID;
  577.     Ptr                    fragEntry, loc;
  578.     Str255                errStr;
  579.     UInt32                origSize, extOrigSize, newSize;
  580.     
  581.     krsrc = GetResource('GLUE', code_boot_glueStrapPPC);
  582.     if (!krsrc) {
  583.         dt_printf(dct, "Can't load boostrap resource, err: %d¥n",
  584.             ResError());
  585.         goto error;
  586.     }
  587.     DetachResource(krsrc);
  588.     HUnlock(krsrc);
  589.     origSize = (UInt32)GetHandleSize(krsrc);
  590.     extOrigSize  = origSize;
  591.     extOrigSize += 0x00000FFFUL;
  592.     extOrigSize &= 0xFFFFF000UL;
  593.     mapSize  += 0x00000FFFUL;
  594.     mapSize  &= 0xFFFFF000UL;
  595.     /* we add a page size */
  596.     newSize      = extOrigSize + mapSize + g_page_size;
  597.     SetHandleSize(krsrc, (SInt32)newSize);
  598.     if (GetHandleSize(krsrc) != newSize) {
  599.         dt_printf(dct, "Can't resize boostrap, err: %d¥n",
  600.             MemError());
  601.         DisposeHandle(krsrc);
  602.         goto error;
  603.     }
  604.     HLock(krsrc);
  605.     
  606.     loc = *krsrc;
  607.     loc = (Ptr)PAGE_ALIGN(loc);
  608.     if (loc != *krsrc) {
  609.         dt_printf(dct, "Boostrap moved from 0x%lx to 0x%lx¥n",
  610.             *krsrc, loc);
  611.         BlockMove(*krsrc, loc, (SInt32)origSize);
  612.     }
  613.     *outMapBegin = (UInt32*)(loc + extOrigSize);
  614.     *outTotalSize = newSize;
  615.     
  616.     err = GetMemFragment(loc, origSize, "¥pbootstrap", kPrivateCFragCopy, &fragID, &fragEntry, errStr);
  617.     if (err != noErr) {
  618.         dt_printf(dct, "Boostrap preparation failed, err: %d (%#s)¥n",
  619.             err, errStr);
  620.         DisposeHandle(krsrc);
  621.         goto error;
  622.     }
  623.     
  624.     return ((void **)fragEntry)[0];
  625.     
  626. error:
  627.     return NULL;
  628. //#endif    
  629. }
  630.  
  631. #if BOOTX_USES_BUFPTR
  632.  
  633. /* This function allocates memory by moving down the BufPtr low memory globals. This
  634.  * is a special technique for use _only_ by system extensions that need a large amount
  635.  * that won't be available in the system heap. That's our case. The strange formula
  636.  * we use with MemTop comes from the MacOS historical roots, the system will make sure
  637.  * that MemTop has a correct value for this formula to apply.
  638.  * Note that this memory will be pageable.
  639.  */
  640. Ptr
  641. alloc_high_mem(unsigned long count)
  642. {
  643.     Ptr limit = (Ptr)((UInt32)LMGetMemTop()/2 + 1024);
  644.     Ptr bufPtr = LMGetBufPtr();
  645.     
  646.     count += 256;
  647.     
  648.     if ((bufPtr - limit) < count)
  649.         return NULL;
  650.     
  651.     LMSetBufPtr(bufPtr - count);
  652.     
  653.     bufPtr -= count;
  654.     
  655.     return (Ptr)(((UInt32)bufPtr | 0xFFUL) + 1);
  656. }
  657.  
  658. #endif // BOOTX_USES_BUFPTR
  659.  
  660. void
  661. setup_basic_bootinfo(boot_infos_t* bi, UInt32 *out_load_base)
  662. {
  663.     long response;
  664.     Boolean arch_pci;
  665.     OSErr    err;
  666.     
  667.     memset(bi, 0, sizeof(boot_infos_t));
  668.  
  669.     bi->version                    = BOOT_INFO_VERSION;
  670.     bi->compatible_version        = BOOT_INFO_COMPATIBLE_VERSION;
  671.  
  672.     // Fill some fields of the boot_infos
  673.     err = Gestalt(gestaltMachineType, (long *)&bi->machineID);
  674.     if (err != noErr)
  675.         bi->machineID = 0;
  676.     bi->architecture = 0;
  677.  
  678.     arch_pci = false;
  679.     if (Gestalt(gestaltOpenFirmwareInfo, &response) == noErr)
  680.         if (Gestalt(gestaltNameRegistryVersion, &response) == noErr)
  681.             arch_pci = true;
  682.  
  683.     // Setup arch flags and memory map for NuBus 
  684.     if (arch_pci) {
  685.         bi->architecture |= BOOT_ARCH_PCI;
  686.         *out_load_base = 0;
  687.         bi->physMemoryMapSize = 0;
  688.     } else {
  689.         build_memory_map(bi);
  690.         bi->architecture |= BOOT_ARCH_NUBUS;
  691.         /* FIXME: Should be smarter about finding a location */
  692.         *out_load_base = 0x200000;
  693.         switch(bi->machineID) {
  694.             case gestaltPowerMac6100_60:
  695.             case gestaltPowerMac6100_66:
  696.             case 101: /* gestaltPowerMac6100_80 */
  697.             case gestaltPowerMac7100_66:
  698.             case gestaltPowerMac7100_80:
  699.             case 113: /* gestaltPowerMac7100_80_chipped */
  700.             case gestaltPowerMac8100_80:
  701.             case gestaltPowerMac8100_100:
  702.             case gestaltPowerMac8100_110:
  703.             case gestaltPowerMac8100_120:
  704.             case gestaltAWS9150_80:
  705.             case gestaltAWS9150_120:
  706.                 bi->architecture |= BOOT_ARCH_NUBUS_PDM;
  707.                 break;
  708.             case gestaltPowerMac5200:
  709.             case gestaltPowerMac6200:
  710.                 bi->architecture |= BOOT_ARCH_NUBUS_PERFORMA;
  711.                 break;
  712.             case gestaltPowerBook1400:
  713.             case gestaltPowerBook5300:
  714.             case gestaltPowerBookDuo2300:
  715.                 bi->architecture |= BOOT_ARCH_NUBUS_POWERBOOK;
  716.                 break;
  717.             /* No default case, we let the kernel boot unsupported machines,
  718.                just in case... */
  719.         }
  720.     }
  721. }
  722.  
  723. UInt32
  724. get_temp_page(UInt32 *cur_temp, UInt32 *used_map, UInt32 used_size)
  725. {
  726.     UInt32    page = *cur_temp;
  727.     UInt32    i;
  728.  
  729. again:
  730.     for (i=0; i<used_size; i++)
  731.         if (used_map[i] == page)
  732.         {
  733.             page += g_page_size;
  734.             goto again;
  735.         }
  736.         
  737.     *cur_temp = page + g_page_size;
  738.     
  739.     return page;
  740. }
  741.  
  742. void
  743. make_kernel_copymap(UInt32* map, UInt32 map_size, UInt32 *map_loc, UInt32 dest_base, UInt32 *temp_page)
  744. {
  745.     UInt32 i,j,k;
  746.     
  747.     dt_printf(dct, "Making kernel copy map...¥n");
  748.  
  749.     k = 0;
  750.     for(i=0; i<map_size; i++) {
  751.         UInt32    src_page    = map[i];
  752.         UInt32    dst_page    = dest_base + (g_page_size * i);
  753.         
  754.         if (src_page == dst_page)
  755.             continue;
  756.             
  757.         /* Check if the destination overlaps a yet uncopied page */
  758.         for (j=i+1; j<map_size; j++) {
  759.             if (dst_page == map[j]) {
  760.                 /* It overlaps. We add a "temp" copy of the dest page */
  761.                 map_loc[k++] = dst_page;
  762.                 map_loc[k++] = map[j] = get_temp_page(temp_page, map+i, map_size-i);
  763.                 map_loc[k++] = g_page_size;
  764.                 dt_printf(dct, "T 0x%08lx -> 0x%08lx¥n", map_loc[k-3], map_loc[k-2]);
  765.                 break;
  766.             }
  767.         }
  768.         map_loc[k++] = src_page;
  769.         map_loc[k++] = dst_page;
  770.         map_loc[k++] = g_page_size;
  771.     }
  772.     map_loc[k++] = 0;
  773.     map_loc[k++] = 0;
  774.     map_loc[k++] = 0;
  775.  
  776.     dt_printf(dct, "list of %d copies for %d pages¥n", ((k-1)/3), map_size);
  777. }
  778.  
  779. #if BOOTX_ENV == BOOTX_ENV_APPLICATION
  780.  
  781. /* Send a restart event to the finder */
  782. OSErr
  783. send_restart_to_finder(void)
  784. {
  785.     OSErr                    err = noErr;
  786.     ProcessSerialNumber        sn;
  787.     AEDesc                    address;
  788.     AppleEvent                theAE, reply;
  789.     
  790.     err = find_finder_process(&sn);
  791.     
  792.     if ( err == noErr )    err = AECreateDesc( typeProcessSerialNumber, &sn, sizeof( ProcessSerialNumber ), &address );
  793.     if ( err == noErr ) err = AECreateAppleEvent( kFinderSig, 'rest', &address, kAutoGenerateReturnID, kAnyTransactionID, &theAE);
  794.     if ( err == noErr ) err = AESend( &theAE, &reply, kAENoReply + kAECanInteract + kAECanSwitchLayer, kAENormalPriority, kAEDefaultTimeout, nil, nil );
  795.  
  796.     return err;
  797. }
  798.  
  799. /* We look for the Finder in the list of processes */
  800. OSErr
  801. find_finder_process(ProcessSerialNumberPtr processSN)
  802. {
  803.     ProcessInfoRec tempInfo;
  804.     FSSpec procSpec;
  805.     Str31 processName;
  806.     OSErr myErr = noErr;
  807.  
  808.     /* nul out the PSN so we're starting at the beginning of the list */
  809.     processSN->lowLongOfPSN = kNoProcess;
  810.     processSN->highLongOfPSN = kNoProcess;
  811.  
  812.     /* initialize the process information record */
  813.     tempInfo.processInfoLength = sizeof(ProcessInfoRec);
  814.     tempInfo.processName = (unsigned char *)&processName;
  815.     tempInfo.processAppSpec = &procSpec;
  816.     /* loop through all the processes until we */
  817.     /* 1) find the process we want */
  818.     /* 2) error out because of some reason (usually, no more processes */
  819.     do {
  820.         myErr = GetNextProcess(processSN);
  821.         if (myErr == noErr)
  822.             GetProcessInformation(processSN, &tempInfo);
  823.         
  824.         if ( tempInfo.processSignature == 'MACS' && tempInfo.processType == 'FNDR' )
  825.             break;
  826.         
  827.     } while ( myErr == noErr );
  828.  
  829.     return( myErr );
  830. }
  831.  
  832. #endif // BOOTX_ENV == BOOTX_ENV_APPLICATION
  833.  
  834. OSErr
  835. do_load_glues(Ptr *low_68k_glue, Ptr *low_PPC_glue)
  836. {
  837.     Handle    rsrc;
  838.     OSErr    err;
  839.     
  840.     // Just in case it was not the case
  841.     SetZone(SystemZone());
  842.     
  843.     if (low_68k_glue) {
  844.         rsrc = Get1Resource('GLUE', code_boot_glue68k);
  845.         if (rsrc == NULL) {
  846.             err = ResError();
  847.             if (err == noErr) err = memFullErr;
  848.             return err;
  849.         }
  850.         HNoPurge(rsrc);
  851.         DetachResource(rsrc);
  852.         HLock(rsrc);
  853.         *low_68k_glue = *rsrc;
  854.     }
  855.     
  856.     if (low_PPC_glue) {    
  857.         rsrc = Get1Resource('GLUE', code_boot_gluePrePPC);
  858.         if (rsrc == NULL) {
  859.             err = ResError();
  860.             if (err == noErr) err = memFullErr;
  861.             return err;
  862.         }
  863.         HNoPurge(rsrc);
  864.         DetachResource(rsrc);
  865.         HLock(rsrc);
  866.         *low_PPC_glue = *rsrc;
  867.     }
  868.     return noErr;
  869. }
  870.  
  871. void
  872. add_l2cr_property(UInt32 l2cr_value)
  873. {
  874.     RegEntryIter            iterator;
  875.     RegEntryIterationOp        operation;
  876.     OSStatus                err;
  877.     Boolean                    done, found;
  878.     char                    buffer[1024];
  879.     RegEntryID                root_node_id;
  880.     RegEntryID                entryID;
  881.     Boolean                    first;
  882.     
  883.     dt_printf(dct, "Setting L2CR override to 0x%08lx¥n", l2cr_value);
  884.     
  885.     // Create an Iterator
  886.     operation = kRegIterContinue;    
  887.     err = RegistryEntryIterateCreate(&iterator);
  888.     if (err != noErr) {
  889.         dt_printf(dct, " #Can't create iterator !¥n");
  890.         return;
  891.     }    
  892.     err = RegistryEntryIDInit(&root_node_id);
  893.     if (err != noErr) {
  894.         dt_printf(dct, " #Can't init root id !¥n");
  895.         RegistryEntryIterateDispose(&iterator);
  896.         return;
  897.     }
  898.  
  899.     err = RegistryCStrEntryLookup(NULL, "Devices:device-tree", &root_node_id);
  900.     if (err != noErr) {
  901.         dt_printf(dct, " #Can't find device tree root !¥n");
  902.         RegistryEntryIDDispose(&root_node_id);
  903.         RegistryEntryIterateDispose(&iterator);
  904.         return;
  905.     }
  906.  
  907.     RegistryEntryIterateSet(&iterator, &root_node_id);
  908.     first = true;
  909.     found = false;
  910.     
  911.     do {
  912.         RegPropertyValueSize size;
  913.             
  914.         err = RegistryEntryIterate(&iterator, first ? kRegIterChildren : kRegIterContinue, &entryID, &done);
  915.         first = false;
  916.         if (!done && (err == noErr)) {
  917.             size = 1024;
  918.             err = RegistryPropertyGet(&entryID, "device_type", buffer, &size);
  919.             if (err == noErr) {
  920.                 buffer[size] = 0;
  921.                 dt_printf(dct, " -> type : %s¥n", buffer);
  922.                 if ((strcmp(buffer, "cpus") == 0) || (strcmp(buffer, "cpu") == 0)) {
  923.                     dt_printf(dct, " -> Found !¥n", buffer);
  924.                     found = true;
  925.                     err = RegistryPropertyCreate(&entryID, "l2cr-value", &l2cr_value, 4);
  926.                     if (err != noErr) {
  927.                         dt_printf(dct, " #Error %d creating property¥n", err);
  928.                     }
  929.                     break;
  930.                 }
  931.             }
  932.         }
  933.     } while (!done && !found && (err == noErr));
  934.  
  935.     RegistryEntryIterateDispose(&iterator);
  936.     RegistryEntryIDDispose(&root_node_id);
  937. }
  938.  
  939. #if BOOTX_ENV != BOOTX_ENV_RAW
  940.  
  941. void
  942. check_burgundy_patch(void)
  943. {
  944.     Ptr                    patchPtr;
  945.     THz                    oldZone;
  946.     Handle                patchRsrc;
  947.     
  948.     oldZone = GetZone();
  949.     SetZone(SystemZone());
  950.     
  951.     patchRsrc = Get1Resource('GLUE', code_boot_glueBurgundy);
  952.     if (patchRsrc == NULL) {
  953.         goto bail;
  954.     }
  955.     DetachResource(patchRsrc);
  956.     HLock(patchRsrc);
  957.     patchPtr = *patchRsrc;
  958.  
  959.     if (!CallUniversalProc((RoutineDescriptor *)patchPtr,
  960.         kCStackBased | RESULT_SIZE(SIZE_CODE(sizeof(Boolean))))) {
  961.         HUnlock(patchRsrc);
  962.         DisposeHandle(patchRsrc);
  963.     }    
  964.  
  965. bail:
  966.     SetZone(oldZone);
  967. }
  968.  
  969. #endif // BOOTX_ENV != BOOTX_ENV_RAW
  970.  
  971.  
  972. #pragma mark -
  973.  
  974.  
  975. Boolean
  976. check_kernel_file(    boot_file_t            *in_file,
  977.                     boot_kernel_desc_t    *out_kernel_infos,
  978.                     boot_ramdisk_desc_t    *out_ramdisk_infos,
  979.                     Boolean                *out_has_ramdisk)
  980. {
  981.     Elf32_Ehdr    *e;
  982.     struct        external_filehdr* xc;
  983.     UInt32        size;
  984.     OSErr        err;
  985.     
  986.     *out_has_ramdisk            = false;
  987.     out_kernel_infos->file        = NULL;
  988.     out_ramdisk_infos->file        = NULL;
  989.  
  990.     /* Open kernel file */
  991.     err = file_open(in_file);
  992.     if (err != noErr) {
  993.         dt_printf(dct, "#check_kernel_file: file_open(%#s) returned %d¥n",
  994.             in_file->name, err);
  995.         return false;
  996.     }
  997.  
  998.     /* Read first KB into buffer for header */
  999.     size = TEMP_BUFFER_SIZE;
  1000.     err = file_read(in_file, 0, s_temp_buffer, &size);
  1001.     if (err != noErr) {
  1002.         dt_printf(dct, "#check_kernel_file: can't read first Kb of file (%#s), error %d¥n",
  1003.             in_file->name , err);
  1004.         goto fail;
  1005.     }
  1006.     
  1007.     /* Check if it is a Mach Kernel Image */
  1008.     if (strncmp("MACH_BOOT_IMAGE", (char *) s_temp_buffer, 15) == 0) {
  1009.         dt_printf(dct, "Found Mach Kernel Image (%#s)¥n", in_file->name);
  1010.         
  1011.         out_kernel_infos->file        = in_file;
  1012.         out_kernel_infos->zImage    = false;
  1013.         /* These are filled later */
  1014.         out_kernel_infos->offset    = 0;
  1015.         out_kernel_infos->size        = 0;
  1016.         out_kernel_infos->mem_size    = 0;
  1017.         out_kernel_infos->entry        = 0;
  1018.         out_kernel_infos->load_base    = 0;
  1019.         
  1020.         goto found;
  1021.     }
  1022.     
  1023.     e = (Elf32_Ehdr *)s_temp_buffer;
  1024.     xc = (struct external_filehdr *)s_temp_buffer;
  1025.     
  1026.     /* Check if it is an executable elf binary. */
  1027.     if (e->e_ident[EI_MAG0] == ELFMAG0 && e->e_ident[EI_MAG1] == ELFMAG1 &&
  1028.           e->e_ident[EI_MAG2] == ELFMAG2 && e->e_ident[EI_MAG3] == ELFMAG3) {
  1029.         dt_printf(dct, "Found ELF kernel (%#s)¥n", in_file->name);
  1030.         out_kernel_infos->file        = in_file;
  1031.         out_kernel_infos->zImage    = false;
  1032.         /* These are filled later */
  1033.         out_kernel_infos->offset    = 0;
  1034.         out_kernel_infos->size        = 0;
  1035.         out_kernel_infos->mem_size    = 0;
  1036.         out_kernel_infos->entry        = 0;
  1037.         out_kernel_infos->load_base    = 0;
  1038.         
  1039.         goto found;
  1040.     }
  1041.     
  1042.     /* Check if this is an xcoff */
  1043. #define CHECK_MAGIC(xc,m) (get_16be(xc->f_magic) == (m))
  1044.     if ((get_16be(xc->f_magic) == 0735) || (get_16be(xc->f_magic) == 0730)
  1045.         || (get_16be(xc->f_magic) == 0737)) {
  1046.         struct external_scnhdr *sp;
  1047.         struct external_scnhdr *isect, *rsect;
  1048.         int ns, oh, i;
  1049.         
  1050.         dt_printf(dct, "Found compressed XCOFF kernel (zImage : %#s)¥n", in_file->name);
  1051.         out_kernel_infos->file        = in_file;
  1052.         out_kernel_infos->zImage    = true;
  1053.         /* These are filled later */
  1054.         out_kernel_infos->mem_size    = 0;
  1055.         out_kernel_infos->entry        = 0;
  1056.         out_kernel_infos->load_base    = 0;
  1057.  
  1058.         ns = get_16be(xc->f_nscns);
  1059.         oh = get_16be(xc->f_opthdr);
  1060.         
  1061.         /* compensate for eventual alignement */
  1062.         while(ns) {
  1063.             size = (sizeof(struct external_scnhdr)+4) * ns;
  1064.             if (size > TEMP_BUFFER_SIZE) {
  1065.                 dt_printf(dct, "#skipping section !¥n");
  1066.                 ns--;
  1067.             } else
  1068.                 break;
  1069.         }
  1070.         if (ns == 0) {
  1071.             dt_printf(dct, "#skipped all sections !!!¥n");
  1072.             goto fail;
  1073.         }
  1074.             
  1075.         err = file_read(in_file, sizeof(struct external_filehdr) + oh, s_temp_buffer, &size);
  1076.         if (err != noErr) {
  1077.             dt_printf(dct, "#error %d while reading section headers !¥n");
  1078.             goto fail;
  1079.         }
  1080.         
  1081.         sp = (struct external_scnhdr *) s_temp_buffer;
  1082.         isect = rsect = NULL;
  1083.         for (i = 0; i < ns; ++i, ++sp) {
  1084.             dt_printf(dct, "section %d: %s¥n", i, sp->s_name);
  1085.             if (strcmp(sp->s_name, "image") == 0)
  1086.                 isect = sp;
  1087.             else if (strcmp(sp->s_name, "initrd") == 0)
  1088.                 rsect = sp;
  1089.         }
  1090.         if (isect == NULL) {
  1091.             dt_printf(dct, "#image section not found¥n");
  1092.             goto fail;
  1093.         }
  1094.         
  1095.         out_kernel_infos->offset    = get_32be(isect->s_scnptr);
  1096.         out_kernel_infos->size        = get_32be(isect->s_size);
  1097.  
  1098.         if (rsect != NULL) {
  1099.                 *out_has_ramdisk = true;
  1100.                 out_ramdisk_infos->file        = in_file;
  1101.                 out_ramdisk_infos->offset    = get_32be(rsect->s_scnptr);
  1102.                 out_ramdisk_infos->size        = get_32be(rsect->s_size);
  1103.                 dt_printf(dct, "Ramdisk found in image, size: %dKb¥n",
  1104.                     (out_ramdisk_infos->size)/1024);
  1105.         }
  1106.         goto found;
  1107.     }
  1108.         
  1109. fail: /* default */
  1110.     file_close(in_file);    
  1111.     return false;
  1112.  
  1113. found:
  1114.     file_close(in_file);    
  1115.     return true;
  1116. }                            
  1117.  
  1118. Boolean check_ramdisk_file(    boot_file_t            *in_file,
  1119.                             boot_ramdisk_desc_t    *out_ramdisk_infos)
  1120. {
  1121.     OSErr err;
  1122.     
  1123.     /* Open kernel file */
  1124.     err = file_open(in_file);
  1125.     if (err != noErr) {
  1126.         dt_printf(dct, "#check_ramdisk_file: file_open(%#s) returned %d¥n",
  1127.             in_file->name, err);
  1128.         return false;
  1129.     }
  1130.  
  1131.     out_ramdisk_infos->file        = in_file;
  1132.     out_ramdisk_infos->offset    = 0;
  1133.     out_ramdisk_infos->size        = in_file->size;
  1134.     
  1135.     file_close(in_file);
  1136.  
  1137.     return true;
  1138. }
  1139.  
  1140.  
  1141.  
  1142. /* Some macros used by do_boot */
  1143. #if BOOTX_USES_BUFPTR
  1144.     #define    PREPARE_ALLOC()    do {saveBufPtr = LMGetBufPtr(); } while(0)                        
  1145.     #define    FINISH_ALLOC()    do {LMSetBufPtr(saveBufPtr);    } while(0)
  1146.     #define DO_ALLOC(sz)    (alloc_high_mem(sz))    
  1147.     #define DO_FREE(p)
  1148. #else
  1149.     #define    PREPARE_ALLOC()
  1150.     #define    FINISH_ALLOC()
  1151.     #define DO_ALLOC(sz)    (NewPtrSys((SInt32)(sz)))    
  1152.     #define DO_FREE(p)        do {THz _saveZone = GetZone(); SetZone(SystemZone()); ¥
  1153.                                 DisposePtr(p); SetZone(_saveZone); } while(0)
  1154. #endif // BOOTX_USES_BUFPTR
  1155.                             
  1156. #define ki                in_kernel_infos
  1157. #define ri                in_ramdisk_infos
  1158.  
  1159. OSStatus
  1160. do_boot(            boot_kernel_desc_t    *in_kernel_infos,
  1161.                     boot_ramdisk_desc_t    *in_ramdisk_infos,
  1162.                     boot_params_t        *in_params)
  1163. {
  1164.     Ptr                 saveBufPtr = LMGetBufPtr();
  1165.     Ptr                big_stuffs;
  1166.     OSStatus        err;
  1167.     UInt32            offsets[offset_count];
  1168.     Ptr                main_base, gzipped_kernel;
  1169.     UInt32            total_size, ramdisk_size;
  1170.     Ptr                dev_tree;
  1171.     UInt32            dev_tree_size;
  1172.     UInt32            dev_tree_disp_off;
  1173.     void*            strap_entry;
  1174.     UInt32            strap_phys_entry, strap_dest;
  1175.     UInt32            boot_map_addr, strap_size;
  1176.     UInt32            prec, args_len;
  1177.     UInt32*            map;
  1178.     UInt32*            map_loc;
  1179.     UInt32            map_size, start, params;
  1180.     UInt32            load_base, temp_page;
  1181.     void*            boot_glue_PPC;
  1182.     boot_infos_t*    bi;
  1183.     Boolean            resident;
  1184.     Ptr                low_68k_glue;
  1185.     Ptr                low_PPC_glue;
  1186.     static PPCRegisterList    regList;    
  1187.     
  1188.     PREPARE_ALLOC();
  1189.  
  1190.     dev_tree = gzipped_kernel = big_stuffs = NULL;
  1191.     low_68k_glue = NULL;
  1192.     low_PPC_glue = NULL;
  1193.     resident = false;
  1194.  
  1195. #if BOOTX_ENV == BOOTX_ENV_RAW
  1196.     low_68k_glue = (Ptr)low_boot;
  1197. //    low_PPC_glue = g_low_PPC_strap;
  1198.     err = do_load_glues(NULL, &low_PPC_glue);
  1199.     if (err != noErr) {
  1200.         dt_printf(dct, "#do_boot: do_load_glues() failed with error %d¥n", err);
  1201.         goto bail;
  1202.     }
  1203. #else
  1204.     err = do_load_glues(&low_68k_glue, &low_PPC_glue);
  1205.     if (err != noErr) {
  1206.         dt_printf(dct, "#do_boot: do_load_glues() failed with error %d¥n", err);
  1207.         goto bail;
  1208.     }
  1209. #endif
  1210.         
  1211.     if (g_arch_PCI) {    
  1212.         /* Build the copy of the device tree */
  1213.         dt_printf(dct, "Copying device tree...¥n");
  1214.         dev_tree = DO_ALLOC(NAME_REGISTRY_MAX_SIZE);
  1215.         if (dev_tree == NULL) {
  1216.             dt_printf(dct, "#can't allocate room for device tree !¥n");
  1217.             err = memFullErr;
  1218.             goto bail;
  1219.         }
  1220.         
  1221.         if (in_params->override_l2cr)
  1222.             add_l2cr_property(in_params->l2cr_value);
  1223.  
  1224.         err = build_pci_device_tree(dev_tree, &dev_tree_size, &dev_tree_disp_off);
  1225.         if (err != noErr) {
  1226.             dt_printf(dct, "#build_pci_device_tree returned error %d¥n", err);
  1227.             goto bail;
  1228.         }
  1229.         dt_printf(dct, "Device tree is %d bytes at 0x%lx¥n", dev_tree_size, dev_tree);
  1230.     } else
  1231.         dev_tree_size = 0;
  1232.  
  1233.     /* Open the kernel file */
  1234.     if (ki->file->rn == -1) {
  1235.         err = file_open(ki->file);
  1236.         if (err != noErr) {
  1237.             dt_printf(dct, "#do_boot: file_open(%#s) returned %d¥n",
  1238.                 ki->file->name, err);
  1239.             goto bail;
  1240.         }
  1241.     }
  1242.     /* Open the ramdisk file */
  1243.     if (ri && (ri->file->rn == -1)) {
  1244.         err = file_open(ri->file);
  1245.         if (err != noErr) {
  1246.             dt_printf(dct, "#do_boot: file_open(%#s) returned %d¥n",
  1247.                 ri->file->name, err);
  1248.             goto bail;
  1249.         }
  1250.     }
  1251.  
  1252.     /* If we have a compressed kernel, we load it in a buffer and we use
  1253.        an arbitrary memory size of 2*gz_size + 2Mb
  1254.      */
  1255.     if (ki->zImage) {
  1256.         UInt32 sz;
  1257.         gzipped_kernel = DO_ALLOC(ki->size);
  1258.         if (gzipped_kernel == NULL) {
  1259.             dt_printf(dct, "#do_boot: can't allocate room for zImage¥n");
  1260.             err = memFullErr;
  1261.             goto bail;
  1262.         }
  1263.         sz = ki->size;
  1264.         err = file_read(ki->file, ki->offset, gzipped_kernel, &sz);
  1265.         if (err != noErr) {
  1266.             dt_printf(dct, "#do_boot: file_read(%#s) returned %d¥n",
  1267.                 ki->file->name, err);
  1268.             goto bail;
  1269.         }
  1270.         ki->mem_size = (ki->size * 2) + 0x100000;
  1271.     } else {
  1272.         err = check_elf_kernel(ki);
  1273.         if (err != noErr) {
  1274.             dt_printf(dct, "#do_boot: check_elf_kernel failed (err %d) !¥n", err);
  1275.             goto bail;
  1276.         }
  1277.     }
  1278.     
  1279.     /* Fix some values. */
  1280.     if (ri == NULL)
  1281.         ramdisk_size = 0;
  1282.     else
  1283.         ramdisk_size = ri->size;
  1284.         
  1285.     if (in_params == NULL)
  1286.         args_len = 0;
  1287.     else
  1288.         args_len = strlen(in_params->args)+1;
  1289.         
  1290.     /* We build the map of offsets. */
  1291.     offsets[offset_kernel]        = 0;
  1292.     offsets[offset_stack]        = prec = PAGE_ALIGN(ki->mem_size);
  1293.     offsets[offset_bootinfo]    = prec = PAGE_ALIGN(prec + BOOT_KERNEL_STACK_SIZE);
  1294.     offsets[offset_arguments]    = prec = LINE_ALIGN(prec + sizeof(boot_infos_t));
  1295.     offsets[offset_color_map]    = prec = LINE_ALIGN(prec + args_len);
  1296.     offsets[offset_device_tree]    = prec = LINE_ALIGN(prec + BOOTX_COLORTABLE_SIZE);
  1297.     offsets[offset_ramdisk]        = prec = PAGE_ALIGN(prec + dev_tree_size);
  1298.     prec = PAGE_ALIGN(prec + ramdisk_size);
  1299.     total_size = prec + g_page_size;
  1300.     /* We leave some room so that the unmangler won't erase itself */
  1301.     offsets[offset_unmangler]    = total_size + 2*g_page_size;
  1302.     
  1303.     /* We do the final "big block" allocation */
  1304.     big_stuffs = DO_ALLOC(total_size + g_page_size);
  1305.     if (big_stuffs == NULL) {
  1306.         dt_printf(dct, "#do_boot: can't allocate room for kernel¥n");
  1307.         err = memFullErr;
  1308.         goto bail;
  1309.     }
  1310.     main_base = (Ptr)PAGE_ALIGN(big_stuffs);
  1311.     memset(main_base + offsets[offset_stack], 0, BOOT_KERNEL_STACK_SIZE);
  1312.     dt_printf(dct, "Main stuffs base: 0x%x¥n", main_base);
  1313.     
  1314.     /* Load or decompress kernel */
  1315.     if (ki->zImage) {
  1316.         unsigned int    sz = (unsigned int)ki->mem_size;
  1317.         dt_printf(dct, "Unzipping kernel... ¥n");
  1318.         err = gunzip(main_base + offsets[offset_kernel], ki->mem_size,
  1319.             (UInt8 *)gzipped_kernel, &sz);
  1320.         if (err != noErr) {
  1321.             dt_printf(dct, "#do_boot: gunzip failed !¥n");
  1322.             goto bail;
  1323.         }
  1324.         dt_printf(dct, "Kernel using %dKb out of %dKb reserved¥n",
  1325.             sz/1024, ki->mem_size/1024);
  1326.         /* We can now free the temp buffer */
  1327.         DO_FREE(gzipped_kernel);
  1328.         gzipped_kernel = NULL;
  1329.     } else {
  1330.         UInt32    sz = ki->size;
  1331.         err = file_read(ki->file, ki->offset, main_base + offsets[offset_kernel], &sz);
  1332.         if (err != noErr) {
  1333.             dt_printf(dct, "#do_boot: can't load ELF kernel image, err: %d¥n", err);
  1334.             goto bail;
  1335.         }
  1336.     }
  1337.         
  1338.     /* Fix kernel coff entry */    
  1339.     start = *(UInt32 *)(main_base + offsets[offset_kernel] + ki->entry);
  1340.     if ((start < ki->load_base) || (start >= (ki->load_base + ki->mem_size))
  1341.         || (((UInt32 *)(main_base + offsets[offset_kernel] + ki->entry))[2] != 0))
  1342.         /* doesn't look like a procedure descriptor */
  1343.         start = ki->entry + ki->load_base;
  1344.     ki->entry = start - ki->load_base;
  1345.     dt_printf(dct, "Fixed kernel entry: 0x%x¥n", ki->entry);
  1346.  
  1347.     /* We setup the boot-info stucture and fill it */
  1348.     bi = (boot_infos_t *)(main_base + offsets[offset_bootinfo]);
  1349.     setup_basic_bootinfo(bi, &load_base);
  1350.  
  1351.     bi->totalParamsSize            = BI_OFFSET(offset_unmangler);
  1352.     if (args_len) {
  1353.         bi->kernelParamsOffset    = BI_OFFSET(offset_arguments);
  1354.         memcpy(main_base + offsets[offset_arguments], in_params->args, args_len); 
  1355.     } else
  1356.         bi->kernelParamsOffset    = 0;
  1357.  
  1358.     /* Make room for the colormap and store the offset. This offset will be used or cleared
  1359.        when the display device infos are really gathered by the low-level booter */
  1360.     bi->dispDeviceColorsOffset    = BI_OFFSET(offset_color_map);
  1361.  
  1362.     /* Copy in the device tree */
  1363.     bi->deviceTreeOffset            = BI_OFFSET(offset_device_tree);
  1364.     bi->deviceTreeSize                = dev_tree_size;
  1365.     bi->dispDeviceRegEntryOffset    = dev_tree_disp_off;
  1366.     memcpy(main_base + offsets[offset_device_tree], dev_tree, dev_tree_size);
  1367.  
  1368.     /* Copy the ramdisk */
  1369.     if (ramdisk_size) {
  1370.         UInt32 sz = ramdisk_size;
  1371.         dt_printf(dct, "Loading ramdisk (%dKb)¥n", ramdisk_size/1024);
  1372.         err = file_read(ri->file, ri->offset, main_base + offsets[offset_ramdisk], &sz);
  1373.         if (err != noErr) {
  1374.             dt_printf(dct, "#do_boot: can't load ramdisk, err: %d¥n", err);
  1375.             goto bail;
  1376.         }
  1377.         bi->ramDisk                = BI_OFFSET(offset_ramdisk);
  1378.         bi->ramDiskSize            = ramdisk_size;
  1379.     }
  1380.  
  1381. #if BOOTX_ENV != BOOTX_ENV_RAW
  1382.     /* First make all the stuff resident (but not necessarily contiguous) */
  1383.     err = make_resident(main_base, total_size, in_params->no_relocation ? true : false);
  1384.     if (err != noErr) {
  1385.         dt_printf(dct, "#do_boot: can't make stuffs resident, err: %d¥n", err);
  1386.         goto bail;
  1387.     }
  1388.     resident = true;
  1389. #endif // BOOTX_ENV != BOOTX_ENV_RAW
  1390.  
  1391.     if (in_params->no_relocation) {
  1392.     
  1393.         regList.PC        = (UInt32)main_base + offsets[offset_kernel] + (UInt32)ki->entry;
  1394.         regList.GPR[1]    = (UInt32)main_base + offsets[offset_stack] + BOOT_KERNEL_STACK_SIZE - 512;
  1395.         regList.GPR[2]    = 0;
  1396.         regList.GPR[3]    = 'BooX';
  1397.         regList.GPR[4]    = (UInt32)main_base + offsets[offset_bootinfo];
  1398.         regList.GPR[5]    = 0;
  1399.         
  1400.     } else {
  1401.  
  1402.         /* Make a map of pages used by the kernel stuffs */
  1403.         err = make_kernel_map(main_base, total_size, &map, &map_size);
  1404.         if (err != noErr) {
  1405.             dt_printf(dct, "Can't make kernel memory map, error %d¥n", err);
  1406.             goto bail;
  1407.         }
  1408.         dt_printf(dct, "kernel map built, %d entries, loading bootsrap...¥n", map_size);
  1409.  
  1410.         // the map size is multiplied by 2 to make room for "temp" copy
  1411.         // operations that will be generated when source pages overlap
  1412.         // destination. It's then multiplied by 12 which is the size of
  1413.         // an entry in the copy-table.
  1414.         strap_entry = load_bootstrap((map_size + 1) * 24, &map_loc, &strap_size);
  1415.         if (!strap_entry) {
  1416.             err = -1;
  1417.             dt_printf(dct, "#do_boot: failed to bootstrap¥n");
  1418.             goto bail;
  1419.         }
  1420.  
  1421. #if BOOTX_ENV != BOOTX_ENV_RAW
  1422.         // Make the boostrap resident and contiguous
  1423.         err = make_resident(strap_entry, strap_size, true);
  1424.         if (err != noErr) {
  1425.             dt_printf(dct, "#do_boot: can't make bootstrap resident, err %d¥n", err);
  1426.             goto bail;
  1427.         }
  1428. #endif
  1429.             
  1430.         // The boostrap will move itself just after the kernel.
  1431.         strap_size            = PAGE_ALIGN(strap_size);
  1432.         strap_dest            = load_base + offsets[offset_unmangler];
  1433.         strap_phys_entry    = (UInt32)get_physical(strap_entry);
  1434.  
  1435.         // If the bootstrap destination overlaps a kenrel source page, we move
  1436.         // it upward
  1437.         do
  1438.         {
  1439.             int overlap = false;
  1440.             int i;
  1441.             for (i=0; i<map_size; i++)
  1442.                 if ((map[i] >= strap_dest)&&(map[i] < (strap_dest+strap_size))) {
  1443.                     overlap = true;
  1444.                     strap_dest += g_page_size;
  1445.                     dt_printf(dct, "strap overlap 0x%08lx -> 0x%08lx¥n", strap_dest - g_page_size, strap_dest);
  1446.                     break;
  1447.                 }
  1448.             if (!overlap) {
  1449.                 // We also check if the boostrap destination overrides itself (source)
  1450.                 if ((strap_phys_entry < (strap_dest + strap_size)) &&
  1451.                     (strap_phys_entry > (strap_dest - strap_size))) {
  1452.                     strap_dest = PAGE_ALIGN(strap_phys_entry + strap_size);
  1453.                     dt_printf(dct, "strap overlap itself, -> 0x%08lx¥n", strap_dest);
  1454.                 } else
  1455.                     break;
  1456.             }
  1457.         } while(true);
  1458.         offsets[offset_unmangler] = strap_dest - load_base;
  1459.         boot_map_addr = strap_dest + (((UInt32)map_loc) - (UInt32)strap_entry);
  1460.         temp_page = PAGE_ALIGN(strap_dest + strap_size);
  1461.         
  1462.         dt_printf(dct, "strap entry         : 0x%lx¥n", strap_entry);
  1463.         dt_printf(dct, "strap dest          : 0x%lx¥n", strap_dest);
  1464.         dt_printf(dct, "strap phys entry    : 0x%lx¥n", strap_phys_entry);
  1465.         dt_printf(dct, "strap size          : 0x%lx¥n", strap_size);
  1466.  
  1467.         // Now, we build the page-copy list for the bootstrap. For each
  1468.         // kernel page, we first check if the destination already holds
  1469.         // a kernel page. If this is the case, then this page is copied
  1470.         // to a temp buffer, the original copy is done, and the temp
  1471.         // buffer is set to the original source
  1472. #if 1/*BOOTX_ENV != BOOTX_ENV_RAW*/
  1473.         make_kernel_copymap(map, map_size, map_loc, load_base + offsets[offset_kernel], &temp_page);
  1474.         dt_printf(dct, "last copy page dest : 0x%lx¥n", map_size * g_page_size);
  1475. #else
  1476.         map_loc[0] = (UInt32)get_physical(main_base);
  1477.         map_loc[1] = 0; /* g_load_base */
  1478.         map_loc[2] = offsets[offset_unmangler];
  1479.         map_loc[3] = 0;
  1480.         map_loc[4] = 0;
  1481.         map_loc[5] = 0;
  1482. #endif        
  1483.         DisposePtr((Ptr)map);
  1484.         
  1485.         regList.PC        = (unsigned long)strap_entry;
  1486.         regList.GPR[1]    = load_base + offsets[offset_stack] + BOOT_KERNEL_STACK_SIZE - 512;    // The stack for the kernel entry
  1487.         regList.GPR[2]    = 1;                                                    // r2 flag must be set to 1 by BootX 
  1488.         regList.GPR[3]    = 'BooX';                                                // r3 contains 'BooX' ($426F6F58)
  1489.         regList.GPR[4]    = load_base + offsets[offset_bootinfo];                    // r4 contains the boot infos ptr
  1490.         regList.GPR[5]    = NULL; /*iMacHack;*/                                    // r5 NULL, replaced by low-bootsrap with map base of fb
  1491.         regList.GPR[6]    = strap_phys_entry;                                        // r6 contains phys addr. of bootstrap
  1492.         regList.GPR[7]    = strap_dest;                                            // r7 contains dest addr. of bootstrap
  1493.         regList.GPR[8]    = strap_size;
  1494.         regList.GPR[9]    = boot_map_addr;
  1495.         regList.GPR[10]    = ki->entry + load_base + offsets[offset_kernel];
  1496.         regList.GPR[11]    = 0;
  1497.     }
  1498.  
  1499.     // -- Call the low-level PPC boot glue (returns a pointer to an UPP) --
  1500.     //    this call will make sure the code fragment is prepared and returns a pointer
  1501.     //    that can later be called by the 68k code
  1502. #if TARGET_CPU_PPC
  1503.     boot_glue_PPC = (void *)CallUniversalProc((RoutineDescriptor *)
  1504.         low_PPC_glue, kPascalStackBased | RESULT_SIZE(SIZE_CODE(sizeof(void*))));
  1505. #else
  1506.     boot_glue_PPC = ((pascal void*(*)(void))(low_PPC_glue))();
  1507. #endif
  1508.  
  1509. #if BOOTX_ENV != BOOTX_ENV_RAW
  1510.     /* We try to patch the Burgundy driver to prevent it from shutting sound
  1511.        down on iMac and BlueG3s */
  1512.     dt_printf(dct, "Calling burgundy patch...¥n");
  1513.     check_burgundy_patch();
  1514. #endif
  1515.  
  1516.     err = noErr;
  1517.     params = 0;
  1518. #if BOOTX_ENV == BOOTX_ENV_EXTENSION
  1519.     if (in_params && in_params->setup_video)
  1520.         params |= LOW_BOOT_SETUP_VIDEO;
  1521. #endif
  1522.     if (in_params && in_params->force_scsi)
  1523.         params |= LOW_BOOT_FORCE_SCSI_ON;
  1524.     if (in_params && in_params->close_video)
  1525.         params |= LOW_BOOT_CLOSE_VIDEO;
  1526.     if (in_params && in_params->reset_ata)
  1527.         params |= LOW_BOOT_RESET_ATA;
  1528.         
  1529.     debug_checkpoint();
  1530.     
  1531. #if TARGET_CPU_PPC
  1532.     dt_printf(dct, "Switching to 68k bootstrap...¥n");
  1533.     CallUniversalProc((RoutineDescriptor *)low_68k_glue, uppLowLevelBoot68kProcInfo,
  1534.         ®List, bi, boot_glue_PPC, params, dct);
  1535. #else
  1536.     dt_printf(dct, "Calling 68k bootstrap...¥n");
  1537.     ((pascal void(*)(PPCRegisterList*,boot_infos_t*,void*,UInt32,void*))(low_68k_glue))
  1538.         (®List, bi, boot_glue_PPC, params, dct);
  1539. #endif
  1540.  
  1541. #if BOOTX_ENV == BOOTX_ENV_EXTENSION
  1542.     dt_printf(dct, "Shutting machine down...¥n");
  1543.     debug_checkpoint();
  1544.     ShutDwnStart();
  1545. #elif BOOTX_ENV == BOOTX_ENV_APPLICATION
  1546.     dt_printf(dct, "Sending restart event to Finder...¥n");
  1547.     send_restart_to_finder();
  1548. #endif
  1549.  
  1550. bail:
  1551.     if (err != noErr) {
  1552.         if (big_stuffs)
  1553.             DO_FREE(big_stuffs);
  1554.         if (dev_tree)
  1555.             DO_FREE(dev_tree);
  1556.         if (gzipped_kernel)
  1557.             DO_FREE(gzipped_kernel);
  1558.     }
  1559.     
  1560.     if (ki->file->rn != -1)
  1561.         file_close(ki->file);
  1562.     if (ri && ri->file->rn != -1)
  1563.         file_close(ri->file);
  1564.  
  1565.     FINISH_ALLOC();
  1566.  
  1567.     return err;
  1568. }
  1569.